]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
Add Universal Access status indicator
authorGiovanni Campagna <scampa.giovanni@gmail.com>
Wed, 21 Jul 2010 08:44:59 +0000 (10:44 +0200)
committerDan Winship <danw@gnome.org>
Thu, 16 Sep 2010 19:03:26 +0000 (15:03 -0400)
Introduce the Universal Access status indicator as designed, modeled
after the similar UI provided by g-s-d. This indicator allows the user
to change rapidly the keyboard and mouse behaviour (sticky keys, slow
keys, bounce keys, mouse keys), as well as the enabled ATs (magnifier,
screen reader, screen keyboard) and the HighContrast Gtk theme.

https://bugzilla.gnome.org/show_bug.cgi?id=624916

js/Makefile.am
js/ui/magnifier.js
js/ui/main.js
js/ui/panel.js
js/ui/status/accessibility.js [new file with mode: 0644]
tools/build/gnome-shell.modules

index f0efa291fa753a2d1232f246c850c83ad9d40cc8..6412c715d9c86fc24ecada014e6acd72e25e3e94 100644 (file)
@@ -39,6 +39,7 @@ nobase_dist_js_DATA =         \
        ui/search.js            \
        ui/shellDBus.js         \
        ui/statusMenu.js        \
+       ui/status/accessibility.js      \
        ui/telepathyClient.js   \
        ui/tweener.js           \
        ui/windowAttentionHandler.js    \
index 9f42ae86c3a38a5d3160ff70bc0c8e54c3357bc9..e572961a072168a18cc97cbe3b7667244d816f2e 100644 (file)
@@ -6,6 +6,8 @@ const Shell = imports.gi.Shell;
 const St = imports.gi.St;
 const Lang = imports.lang;
 const Mainloop = imports.mainloop;
+const Signals = imports.signals;
+
 const Main = imports.ui.main;
 const MagnifierDBus = imports.ui.magnifierDBus;
 
@@ -112,6 +114,9 @@ Magnifier.prototype = {
         // invisible.
         if (!activate)
             this._xfixesCursor.show();
+
+        // Notify interested parties of this change
+        this.emit('active-changed', activate);
     },
 
     /**
@@ -560,6 +565,7 @@ Magnifier.prototype = {
         }
     }
 };
+Signals.addSignalMethods(Magnifier.prototype);
 
 function ZoomRegion(magnifier, mouseRoot) {
     this._init(magnifier, mouseRoot);
index c4096422636fc7aeea8da2836cab6480c52f55d3..a94ef939059ff119035faf2fa5f16df0e8a80ae1 100644 (file)
@@ -124,6 +124,7 @@ function start() {
     placesManager = new PlaceDisplay.PlacesManager();
     overview = new Overview.Overview();
     chrome = new Chrome.Chrome();
+    magnifier = new Magnifier.Magnifier();
     panel = new Panel.Panel();
     wm = new WindowManager.WindowManager();
     messageTray = new MessageTray.MessageTray();
@@ -173,9 +174,6 @@ function start() {
 
     global.stage.connect('captured-event', _globalKeyPressHandler);
 
-    // Install magnifier.
-    magnifier = new Magnifier.Magnifier();
-
     // Perform initial relayout here
     _relayout();
 
index 767834178994416e2b442a2df365039c8646658a..1abcad0ff142aeff0a0cdeb2c9f538639bee2a45 100644 (file)
@@ -30,21 +30,15 @@ const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
 const SPINNER_UPDATE_TIMEOUT = 130;
 const SPINNER_SPEED = 0.02;
 
-const STANDARD_TRAY_ICON_ORDER = ['keyboard', 'volume', 'bluetooth', 'network', 'battery'];
+const STANDARD_TRAY_ICON_ORDER = ['a11y', 'keyboard', 'volume', 'bluetooth', 'network', 'battery'];
 const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
     'bluetooth-applet': 'bluetooth',
     'gnome-volume-control-applet': 'volume',
     'nm-applet': 'network',
     'gnome-power-manager': 'battery'
 };
-
-/* Holds constructors for shell-implemented SystemStatusButtons
- * example:
- * const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
- *     'network': imports.ui.network.NMApplet
- * };
- */
 const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
+    'a11y': imports.ui.status.accessibility.ATIndicator
 };
 
 const CLOCK_FORMAT_KEY        = 'format';
diff --git a/js/ui/status/accessibility.js b/js/ui/status/accessibility.js
new file mode 100644 (file)
index 0000000..4644f9f
--- /dev/null
@@ -0,0 +1,238 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const DBus = imports.dbus;
+const GConf = imports.gi.GConf;
+const Gio = imports.gi.Gio;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Shell = imports.gi.Shell;
+const Signals = imports.signals;
+const St = imports.gi.St;
+
+const Main = imports.ui.main;
+const PanelMenu = imports.ui.panelMenu;
+const PopupMenu = imports.ui.popupMenu;
+
+const Gettext = imports.gettext.domain('gnome-shell');
+const _ = Gettext.gettext;
+
+const KEY_A11Y_DIR            = "/desktop/gnome/accessibility";
+const KEY_STICKY_KEYS_ENABLED = KEY_A11Y_DIR + "/keyboard/stickykeys_enable";
+const KEY_BOUNCE_KEYS_ENABLED = KEY_A11Y_DIR + "/keyboard/bouncekeys_enable";
+const KEY_SLOW_KEYS_ENABLED   = KEY_A11Y_DIR + "/keyboard/slowkeys_enable";
+const KEY_MOUSE_KEYS_ENABLED  = KEY_A11Y_DIR + "/keyboard/mousekeys_enable";
+
+const AT_SCREEN_KEYBOARD_SCHEMA = "org.gnome.desktop.default-applications.at.mobility";
+const AT_SCREEN_READER_SCHEMA   = "org.gnome.desktop.default-applications.at.visual";
+
+const KEY_FONT_DPI    = "/desktop/gnome/font_rendering/dpi";
+const DPI_LOW_REASONABLE_VALUE  = 50;
+const DPI_HIGH_REASONABLE_VALUE = 500;
+
+const DPI_FACTOR_LARGE   = 1.25;
+const DPI_FACTOR_LARGER  = 1.5;
+const DPI_FACTOR_LARGEST = 2.0;
+const DPI_DEFAULT        = 96;
+
+const KEY_META_DIR       = "/apps/metacity/general";
+const KEY_VISUAL_BELL = KEY_META_DIR + "/visual_bell";
+
+const DESKTOP_INTERFACE_SCHEMA = "org.gnome.desktop.interface";
+const KEY_GTK_THEME      = "gtk-theme";
+const KEY_ICON_THEME     = "icon-theme";
+
+const HIGH_CONTRAST_THEME = "HighContrast";
+
+function getDPIFromX() {
+    let screen = global.get_gdk_screen();
+    if (screen) {
+        let width_dpi = (screen.get_width() / (screen.get_width_mm() / 25.4));
+        let height_dpi = (screen.get_height() / (screen.get_height_mm() / 25.4));
+        if (width_dpi < DPI_LOW_REASONABLE_VALUE
+            || width_dpi > DPI_HIGH_REASONABLE_VALUE
+            || height_dpi < DPI_LOW_REASONABLE_VALUE
+            || height_dpi > DPI_HIGH_REASONABLE_VALUE)
+            return DPI_DEFAULT;
+        else
+            return (width_dpi + height_dpi) / 2;
+    }
+    return DPI_DEFAULT;
+}
+
+function ATIndicator() {
+    this._init.apply(this, arguments);
+}
+
+ATIndicator.prototype = {
+    __proto__: PanelMenu.SystemStatusButton.prototype,
+
+    _init: function() {
+        PanelMenu.SystemStatusButton.prototype._init.call(this, 'preferences-desktop-accessibility', null);
+
+        let client = GConf.Client.get_default();
+        client.add_dir(KEY_A11Y_DIR, GConf.ClientPreloadType.PRELOAD_ONELEVEL, null);
+        client.notify_add(KEY_A11Y_DIR, Lang.bind(this, this._keyChanged), null, null);
+        client.add_dir(KEY_META_DIR, GConf.ClientPreloadType.PRELOAD_ONELEVEL, null);
+        client.notify_add(KEY_META_DIR, Lang.bind(this, this._keyChanged), null, null);
+
+        let highContrast = this._buildHCItem();
+        this.menu.addMenuItem(highContrast);
+
+        let magnifier = this._buildMagItem();
+        this.menu.addMenuItem(magnifier);
+
+        let textZoom = this._buildFontItem(client);
+        this.menu.addMenuItem(textZoom);
+
+        let screenReader = this._buildItem(_("Screen reader"), AT_SCREEN_READER_SCHEMA, 'startup');
+        this.menu.addMenuItem(screenReader);
+
+        let screenKeyboard = this._buildItem(_("Screen keyboard"), AT_SCREEN_KEYBOARD_SCHEMA, 'startup');
+        this.menu.addMenuItem(screenKeyboard);
+
+        let visualBell = this._buildItemGConf(_("Visual alerts"), client, KEY_VISUAL_BELL);
+        this.menu.addMenuItem(visualBell);
+
+        let stickyKeys = this._buildItemGConf(_("Sticky keys"), client, KEY_STICKY_KEYS_ENABLED);
+        this.menu.addMenuItem(stickyKeys);
+
+        let slowKeys = this._buildItemGConf(_("Slow keys"), client, KEY_SLOW_KEYS_ENABLED);
+        this.menu.addMenuItem(slowKeys);
+
+        let bounceKeys = this._buildItemGConf(_("Bounce keys"), client, KEY_BOUNCE_KEYS_ENABLED);
+        this.menu.addMenuItem(bounceKeys);
+
+        let mouseKeys = this._buildItemGConf(_("Mouse keys"), client, KEY_MOUSE_KEYS_ENABLED);
+        this.menu.addMenuItem(mouseKeys);
+
+        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+        this.menu.addAction(_("Universal access settings"), function() {
+            let p = new Shell.Process({ args: ['gnome-control-center','universal-access'] });
+            p.run();
+        });
+    },
+
+    _buildItemExtended: function(string, initial_value, writable, on_set) {
+        let widget = new PopupMenu.PopupSwitchMenuItem(string, initial_value);
+        if (!writable)
+            widget.actor.reactive = false;
+        else
+            widget.connect('toggled', function(item) {
+                on_set(item.state);
+            });
+        return widget;
+    },
+
+    _buildItemGConf: function(string, client, key) {
+        function on_get() {
+            return client.get_bool(key);
+        }
+        let widget = this._buildItemExtended(string,
+            client.get_bool(key),
+            client.key_is_writable(key),
+            function(enabled) {
+                client.set_bool(key, enabled);
+            });
+        this.connect('gconf-changed', function() {
+            widget.setToggleState(client.get_bool(key));
+        });
+        return widget;
+    },
+
+    _buildItem: function(string, schema, key) {
+        let settings = new Gio.Settings({ schema: schema });
+        let widget = this._buildItemExtended(string,
+            settings.get_boolean(key),
+            settings.is_writable(key),
+            function(enabled) {
+                return settings.set_boolean(key, enabled);
+            });
+        settings.connect('changed::'+key, function() {
+            widget.setToggleState(settings.get_boolean(key));
+        });
+        return widget;
+    },
+
+    _buildHCItem: function() {
+        let settings = new Gio.Settings({ schema: DESKTOP_INTERFACE_SCHEMA });
+        let gtkTheme = settings.get_string(KEY_GTK_THEME);
+        let iconTheme = settings.get_string(KEY_ICON_THEME);
+        let hasHC = (gtkTheme == HIGH_CONTRAST_THEME);
+        let highContrast = this._buildItemExtended(
+            _("High Contrast"),
+            hasHC,
+            settings.is_writable(KEY_GTK_THEME) && settings.is_writable(KEY_ICON_THEME),
+            function (enabled) {
+                if (enabled) {
+                    settings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
+                    settings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME);
+                } else {
+                    settings.set_string(KEY_GTK_THEME, gtkTheme);
+                    settings.set_string(KEY_ICON_THEME, iconTheme);
+                }
+            });
+        settings.connect('changed::' + KEY_GTK_THEME, function() {
+            let value = settings.get_string(KEY_GTK_THEME);
+            if (value == HIGH_CONTRAST_THEME) {
+                highContrast.setToggleState(true);
+            } else {
+                highContrast.setToggleState(false);
+                gtkTheme = value;
+            }
+        });
+        settings.connect('changed::' + KEY_ICON_THEME, function() {
+            let value = settings.get_string(KEY_ICON_THEME);
+            if (value != HIGH_CONTRAST_THEME)
+                iconTheme = value;
+        });
+        return highContrast;
+    },
+
+    _buildFontItem: function(client) {
+        let first_gconf_value = client.get_without_default(KEY_FONT_DPI);
+        let default_value = getDPIFromX();
+        let first_value = first_gconf_value ? first_gconf_value.get_float() : default_value;
+        log('default_value = %f, first_value = %f'.format(default_value,first_value));
+        function on_get() {
+            let u_dpi = client.get_float(KEY_FONT_DPI);
+            let x_dpi = getDPIFromX();
+            return (u_dpi - (DPI_FACTOR_LARGE * x_dpi) > -1);
+        }
+        let initial_setting = on_get();
+        let widget = this._buildItemExtended(_("Large text"),
+            initial_setting,
+            client.key_is_writable(KEY_FONT_DPI),
+            function (enabled) {
+                if (enabled)
+                    client.set_float(KEY_FONT_DPI, DPI_FACTOR_LARGE * getDPIFromX());
+                else
+                    client.set_float(KEY_FONT_DPI, (first_value && !initial_setting) ? first_value : default_value);
+            });
+        this.connect('gconf-changed', function() {
+            let active = on_get();
+            if (!active)
+                // setting was modified manually, update it
+                first_value = client.get_value(KEY_FONT_DPI);
+            widget.setToggleState(on_get());
+        });
+        return widget;
+    },
+
+    _buildMagItem: function() {
+        let mag = Main.magnifier;
+        let widget = this._buildItemExtended(_("Zoom screen"),
+            mag.isActive(),
+            true,
+            Lang.bind(mag, mag.setActive));
+        mag.connect('active-changed', function(magnifier, active) {
+            widget.setToggleState(active);
+        });
+        return widget;
+    },
+
+    _keyChanged: function() {
+        this.emit('gconf-changed');
+    }
+};
+Signals.addSignalMethods(ATIndicator.prototype);
index 478b854f808cfbb86eeba9a0c40422d5ccfce4ba..7d6f076ac6c81115bd8d74e7ae2b8acb0616c9dd 100644 (file)
     </dependencies>
   </autotools>
 
+  <autotools id="gsettings-desktop-schemas">
+    <branch repo="git.gnome.org" module="gsettings-desktop-schemas" />
+  </autotools>
+
   <autotools id="gnome-shell">
     <branch repo="git.gnome.org" module="gnome-shell"/>
     <dependencies>
         <dep package="gconf"/>
         <dep package="glib"/>
         <dep package="gnome-desktop-3"/>
+        <dep package="gsettings-desktop-schemas"/>
     </dependencies>
   </autotools>